package com.gonsin.gnews.annotations.model;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.gonsin.gnews.annotations.GNews;
import com.gonsin.gnews.annotations.GNewsField;
import com.gonsin.gnews.annotations.exceptions.GNewsException;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

import java.lang.reflect.Field;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

@Data
@ApiModel("消息结构体")
public class NewsStructPo {

    @ApiModelProperty("消息的唯一标识")
    private String key;

    @ApiModelProperty("消息的名字")
    private String name;

    @ApiModelProperty("消息的标题")
    private String title;

    @ApiModelProperty("作用用户类型")
    private String[] userType;

    @ApiModelProperty("消息包含的参数")
    private List<NewsTemplateParams> params;

    @ApiModelProperty("消息的类")
    @JsonIgnore
    private Class<?> templateClass;

    public NewsStructPo(NewsStructPo n) {
        this.name = n.name;
        this.title = n.title;
        this.userType = n.userType;
        this.key = n.key;
        this.params = new ArrayList<>();
        for(NewsTemplateParams p : n.params){
            this.params.add(new NewsTemplateParams(p));
        }
    }

    public NewsStructPo(Class<?> templateClass) {
        this.templateClass = templateClass;

        GNews news = templateClass.getAnnotation(GNews.class);

        this.params = new ArrayList<>();
        do {
            Field[] fields = templateClass.getDeclaredFields();
            List<NewsTemplateParams> params = new ArrayList<>();
            for(int i = 0; i < fields.length; i++){
                GNewsField newsField = fields[i].getDeclaredAnnotation(GNewsField.class);
                if(newsField == null){
                    continue;
                }
                params.addAll(initParams(templateClass, fields[i], newsField));
            }
            params.forEach(p -> {
                p.setValue("${(" + p.getValue() + ")!}");
            });
            templateClass = templateClass.getSuperclass();
            this.params.addAll(params);
        } while(templateClass != Object.class);

        this.title = news.title();
        this.name = news.name();
        this.key = news.key();
        this.userType = news.userType();
    }

    private static List<String> BASE_TYPE = Arrays.asList(
            "int", "byte", "boolean", "double", "float", "short", "char", "long",
            String.class.getName(),
            Integer.class.getName(),
            Byte.class.getName(),
            Boolean.class.getName(),
            Double.class.getName(),
            Float.class.getName(),
            Short.class.getName(),
            Character.class.getName(),
            Long.class.getName()
    );


    /**
     * 初始化消息参数
     */
    private List<NewsTemplateParams> initParams(Class parentClass, Field field, GNewsField newsField) {
        Type fieldType = field.getGenericType();

        // 判断是否为基础类型
        if(BASE_TYPE.contains(fieldType.getTypeName())){
            NewsTemplateParams newsParams = new NewsTemplateParams();
            newsParams.setKey(newsField.name());
            newsParams.setValue(field.getName());
            newsParams.setDemo(newsField.demo());
            return Collections.singletonList(newsParams);
        }

        if(!(fieldType instanceof Class)){
            throw new GNewsException("被@GNews批注的类不能含有接口类型的成员变量，请查看【%s】里的【%s】字段", parentClass.getName(), field.getName());
        }

        Class clazz = (Class)fieldType;

        String key = field.getName();
        String name = newsField.name();


        Field[] childFields = clazz.getDeclaredFields();
        List<NewsTemplateParams> params = new ArrayList<>();
        for(int i = 0; i < childFields.length; i++){
            GNewsField childNewsField = childFields[i].getDeclaredAnnotation(GNewsField.class);
            if(childNewsField == null){
                continue;
            }
            List<NewsTemplateParams> p = initParams(clazz, childFields[i], childNewsField);
            for(NewsTemplateParams childP : p){
                childP.setValue(key + "." + childP.getValue());
                childP.setKey(name + "-" + childP.getKey());
            }
            params.addAll(p);
        }

        return params;
    }

    @Data
    public static class NewsTemplateParams {

        @ApiModelProperty("参数的名字")
        private String key;

        @ApiModelProperty("参数的key值")
        private String value;

        @ApiModelProperty("参数的例子")
        private String demo;

        /**
         *
         */
        public NewsTemplateParams(NewsTemplateParams p) {
           this.key = p.key;
           this.value = p.value;
           this.demo = p.demo;
        }
        public NewsTemplateParams() {
        }
    }

}
